﻿/* 
This file is part of Ingo Karstein's Long Path Support project

**Do not remove this comment**

Please see the project homepage at CodePlex:
  http://longpathsupport.codeplex.com/

Please see my blog:
  http://ikarstein.wordpress.com

This code is used in the project "RoboPowerCopy"
  http://robopowercopy.codeplex.com

Licence: GPLv2
    Ingo Karstein's SharePoint 2010 Custom Ribbon Demo
    Copyright (C) 2011  Ingo Karstein, ikarstein@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

internal static class FileTimeHelper
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool GetFileTime(SafeFileHandle hFile, ref FILETIME lpCreationTime,
       ref FILETIME lpLastAccessTime, ref FILETIME lpLastWriteTime);

    [StructLayout(LayoutKind.Sequential)]
    private struct FILETIME
    {
        public uint dwLowDateTime;
        public uint dwHighDateTime;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SYSTEMTIME
    {
        [MarshalAs(UnmanagedType.U2)]
        public short Year;
        [MarshalAs(UnmanagedType.U2)]
        public short Month;
        [MarshalAs(UnmanagedType.U2)]
        public short DayOfWeek;
        [MarshalAs(UnmanagedType.U2)]
        public short Day;
        [MarshalAs(UnmanagedType.U2)]
        public short Hour;
        [MarshalAs(UnmanagedType.U2)]
        public short Minute;
        [MarshalAs(UnmanagedType.U2)]
        public short Second;
        [MarshalAs(UnmanagedType.U2)]
        public short Milliseconds;

        public SYSTEMTIME(DateTime dt, DateTimeKind kind)
        {
            if( kind == DateTimeKind.Utc )
                dt = dt.ToUniversalTime();  // SetSystemTime expects the SYSTEMTIME in UTC

            Year = (short)dt.Year;
            Month = (short)dt.Month;
            DayOfWeek = (short)dt.DayOfWeek;
            Day = (short)dt.Day;
            Hour = (short)dt.Hour;
            Minute = (short)dt.Minute;
            Second = (short)dt.Second;
            Milliseconds = (short)dt.Millisecond;
        }

        public DateTime ToUTC()
        {
            DateTime t = new DateTime(this.Year, this.Month, this.Day, this.Hour, this.Minute, this.Second, this.Milliseconds, DateTimeKind.Utc);
            return t;
        }

        public DateTime ToLocal()
        {
            DateTime t = new DateTime(this.Year, this.Month, this.Day, this.Hour, this.Minute, this.Second, this.Milliseconds, DateTimeKind.Local);
            return t;
        }
    }

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool FileTimeToSystemTime(ref FILETIME lpFileTime,
       out SYSTEMTIME lpSystemTime);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool SystemTimeToFileTime(ref SYSTEMTIME lpSystemTime,
       out FILETIME lpFileTime);

    [Flags]
    public enum EFileAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000,
    }

    [Flags]
    public enum EFileShare : uint
    {
        None = 0x00000000,
        Read = 0x00000001,
        Write = 0x00000002,
        Delete = 0x00000004,
    }

    public enum ECreationDisposition : uint
    {
        New = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5,
    }

    [Flags]
    public enum EFileAttributes : uint
    {
        Readonly = 0x00000001,
        Hidden = 0x00000002,
        System = 0x00000004,
        Directory = 0x00000010,
        Archive = 0x00000020,
        Device = 0x00000040,
        Normal = 0x00000080,
        Temporary = 0x00000100,
        SparseFile = 0x00000200,
        ReparsePoint = 0x00000400,
        Compressed = 0x00000800,
        Offline = 0x00001000,
        NotContentIndexed = 0x00002000,
        Encrypted = 0x00004000,
        Write_Through = 0x80000000,
        Overlapped = 0x40000000,
        NoBuffering = 0x20000000,
        RandomAccess = 0x10000000,
        SequentialScan = 0x08000000,
        DeleteOnClose = 0x04000000,
        BackupSemantics = 0x02000000,
        PosixSemantics = 0x01000000,
        OpenReparsePoint = 0x00200000,
        OpenNoRecall = 0x00100000,
        FirstPipeInstance = 0x00080000
    }

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern SafeFileHandle CreateFile(
        string lpFileName,
        EFileAccess dwDesiredAccess,
        EFileShare dwShareMode,
        IntPtr lpSecurityAttributes,
        ECreationDisposition dwCreationDisposition,
        EFileAttributes dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(
        SafeFileHandle hObject
    );

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool SystemTimeToTzSpecificLocalTime(IntPtr
       lpTimeZoneInformation, ref SYSTEMTIME lpUniversalTime,
       out SYSTEMTIME lpLocalTime);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool TzSpecificLocalTimeToSystemTime(IntPtr
       lpTimeZoneInformation, ref SYSTEMTIME lpLocalTime,
       out SYSTEMTIME lpUniversalTime);

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetFileTime(SafeFileHandle hFile, IntPtr lpCreationTime, IntPtr lpLastAccessTime, IntPtr lpLastWriteTime);

    public static DateTime MinimumTime;
    public static DateTime MinimumTimeUtc;

    static FileTimeHelper()
    {
        MinimumTimeUtc = new DateTime(1601, 01, 01, 00, 00, 00, 00, DateTimeKind.Utc);
        MinimumTime = MinimumTimeUtc.ToLocalTime();
    }

    public static bool GetDirectoryTimesUtc(string DirectoryName, out DateTime CreationTimeUtc, out DateTime LastAccessTimeUtc, out DateTime LastWriteTimeUtc)
    {
        SafeFileHandle ptr = null;
        CreationTimeUtc = MinimumTimeUtc;
        LastAccessTimeUtc = MinimumTimeUtc;
        LastWriteTimeUtc = MinimumTimeUtc;


        try
        {
            ptr = CreateFile(DirectoryName + "\0", EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return GetFileTimesUtc(ptr, out CreationTimeUtc, out LastAccessTimeUtc, out LastWriteTimeUtc);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool GetDirectoryTimes(string DirectoryName, out DateTime CreationTime, out DateTime LastAccessTime, out DateTime LastWriteTime)
    {
        SafeFileHandle ptr = null;
        CreationTime = MinimumTime;
        LastAccessTime = MinimumTime;
        LastWriteTime = MinimumTime;

        try
        {
            ptr = CreateFile(DirectoryName + "\0", EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return GetFileTimes(ptr, out CreationTime, out LastAccessTime, out LastWriteTime);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool GetFileTimesUtc(string FileName, out DateTime CreationTimeUtc, out DateTime LastAccessTimeUtc, out DateTime LastWriteTimeUtc)
    {
        SafeFileHandle ptr = null;
        CreationTimeUtc = MinimumTimeUtc;
        LastAccessTimeUtc = MinimumTimeUtc;
        LastWriteTimeUtc = MinimumTimeUtc;

        try
        {
            ptr = CreateFile(FileName, EFileAccess.GenericRead, EFileShare.Read, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return GetFileTimesUtc(ptr, out CreationTimeUtc, out LastAccessTimeUtc, out LastWriteTimeUtc);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool GetFileTimesUtc(SafeFileHandle file, out DateTime CreationTimeUtc, out DateTime LastAccessTimeUtc, out DateTime LastWriteTimeUtc)
    {
        CreationTimeUtc = MinimumTimeUtc;
        LastAccessTimeUtc = MinimumTimeUtc;
        LastWriteTimeUtc = MinimumTimeUtc;

        if( file == null || file.IsInvalid || file.IsClosed )
            return false;

        FILETIME ftCreationTime = new FILETIME();
        FILETIME ftLastAccessTime = new FILETIME();
        FILETIME ftLastWriteTime = new FILETIME();
        try
        {
            if( GetFileTime(file, ref ftCreationTime, ref ftLastAccessTime, ref ftLastWriteTime) != true )
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            SYSTEMTIME sCreationTime, sLastAccessTime, sLastWriteTime;

            if( !FileTimeToSystemTime(ref ftCreationTime, out sCreationTime) )
                return false;

            if( !FileTimeToSystemTime(ref ftLastAccessTime, out sLastAccessTime) )
                return false;

            if( !FileTimeToSystemTime(ref ftLastWriteTime, out sLastWriteTime) )
                return false;

            CreationTimeUtc = sCreationTime.ToUTC();
            LastAccessTimeUtc = sLastAccessTime.ToUTC();
            LastWriteTimeUtc = sLastWriteTime.ToUTC();

            return true;
        }
        catch
        {
            return false;
        }
        finally
        {
        }
    }

    public static bool GetFileTimes(string FileName, out DateTime CreationTime, out DateTime LastAccessTime, out DateTime LastWriteTime)
    {
        SafeFileHandle ptr = null;
        CreationTime = MinimumTime;
        LastAccessTime = MinimumTime;
        LastWriteTime = MinimumTime;

        try
        {
            ptr = CreateFile(FileName, EFileAccess.GenericRead, EFileShare.Read, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return GetFileTimes(ptr, out CreationTime, out LastAccessTime, out LastWriteTime);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool GetFileTimes(SafeFileHandle file, out DateTime CreationTime, out DateTime LastAccessTime, out DateTime LastWriteTime)
    {
        CreationTime = MinimumTime;
        LastAccessTime = MinimumTime;
        LastWriteTime = MinimumTime;

        if( file == null || file.IsInvalid || file.IsClosed )
            return false;

        FILETIME ftCreationTime = new FILETIME();
        FILETIME ftLastAccessTime = new FILETIME();
        FILETIME ftLastWriteTime = new FILETIME();
        try
        {
            if( GetFileTime(file, ref ftCreationTime, ref ftLastAccessTime, ref ftLastWriteTime) != true )
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            SYSTEMTIME sCreationTime, sLastAccessTime, sLastWriteTime;
            SYSTEMTIME slCreationTime, slLastAccessTime, slLastWriteTime;

            if( !FileTimeToSystemTime(ref ftCreationTime, out sCreationTime) )
                return false;

            if( !FileTimeToSystemTime(ref ftLastAccessTime, out sLastAccessTime) )
                return false;

            if( !FileTimeToSystemTime(ref ftLastWriteTime, out sLastWriteTime) )
                return false;

            if( !SystemTimeToTzSpecificLocalTime(IntPtr.Zero, ref sCreationTime, out slCreationTime) )
                return false;

            if( !SystemTimeToTzSpecificLocalTime(IntPtr.Zero, ref sLastAccessTime, out slLastAccessTime) )
                return false;

            if( !SystemTimeToTzSpecificLocalTime(IntPtr.Zero, ref sLastWriteTime, out slLastWriteTime) )
                return false;

            CreationTime = slCreationTime.ToLocal();
            LastAccessTime = slLastAccessTime.ToLocal();
            LastWriteTime = slLastWriteTime.ToLocal();
            return true;
        }
        catch
        {
            return false;
        }
        finally
        {
        }
    }

    public static bool SetDirectoryTimes(string DirectoryName, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime)
    {
        SafeFileHandle ptr = null;
        try
        {
            ptr = CreateFile(DirectoryName + "\0", EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);

            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return SetFileTimes(ptr, creationTime, lastAccessTime, lastWriteTime);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool SetDirectoryTimesUtc(string DirectoryName, DateTime? creationTimeUtc, DateTime? lastAccessTimeUtc, DateTime? lastWriteTimeUtc)
    {
        SafeFileHandle ptr = null;
        try
        {
            ptr = CreateFile(DirectoryName + "\0", EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);

            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return SetFileTimesUtc(ptr, creationTimeUtc, lastAccessTimeUtc, lastWriteTimeUtc);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool SetFileTimes(string FileName, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime)
    {
        SafeFileHandle ptr = null;
        try
        {
            ptr = CreateFile(FileName, EFileAccess.GenericWrite, EFileShare.Read, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return SetFileTimes(ptr, creationTime, lastAccessTime, lastWriteTime);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool SetFileTimes(SafeFileHandle file, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime)
    {
        if( file == null || file.IsInvalid || file.IsClosed )
            return false;

        IntPtr iftCreationTime = IntPtr.Zero, iftLastAccessTime = IntPtr.Zero, iftLastWriteTime = IntPtr.Zero;
        try
        {
            FILETIME? ftCreationTime = null;
            FILETIME? ftLastAccessTime = null;
            FILETIME? ftLastWriteTime = null;

            if( creationTime != null )
            {
                DateTime ct = (DateTime)creationTime;
                if( ct >= MinimumTime )
                {

                    SYSTEMTIME slCt = new SYSTEMTIME(ct, DateTimeKind.Local);
                    SYSTEMTIME sCt;
                    FILETIME fCt;

                    if( !TzSpecificLocalTimeToSystemTime(IntPtr.Zero, ref slCt, out sCt) )
                        return false;

                    if( !SystemTimeToFileTime(ref sCt, out fCt) )
                        return false;

                    ftCreationTime = fCt;

                    iftCreationTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftCreationTime, iftCreationTime, false);
                }
            }

            if( lastAccessTime != null )
            {
                DateTime lat = (DateTime)lastAccessTime;

                if( lat >= MinimumTime )
                {
                    SYSTEMTIME slLat = new SYSTEMTIME(lat, DateTimeKind.Local);
                    SYSTEMTIME sLat;
                    FILETIME fLat;

                    if( !TzSpecificLocalTimeToSystemTime(IntPtr.Zero, ref slLat, out sLat) )
                        return false;

                    if( !SystemTimeToFileTime(ref sLat, out fLat) )
                        return false;

                    ftLastAccessTime = fLat;

                    iftLastAccessTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftLastAccessTime, iftLastAccessTime, false);
                }
            }

            if( lastWriteTime != null )
            {
                DateTime lwt = (DateTime)lastWriteTime;

                if( lwt >= MinimumTime )
                {

                    SYSTEMTIME slLwt = new SYSTEMTIME(lwt, DateTimeKind.Local);
                    SYSTEMTIME sLwt;
                    FILETIME fLwt;

                    if( !TzSpecificLocalTimeToSystemTime(IntPtr.Zero, ref slLwt, out sLwt) )
                        return false;

                    if( !SystemTimeToFileTime(ref sLwt, out fLwt) )
                        return false;

                    ftLastWriteTime = fLwt;

                    iftLastWriteTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftLastWriteTime, iftLastWriteTime, false);
                }
            }

            if( SetFileTime(file, iftCreationTime, iftLastAccessTime, iftLastWriteTime) != true )
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            return true;
        }
        catch
        {
            return false;
        }
        finally
        {
            if( iftCreationTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftCreationTime);
            if( iftLastAccessTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftLastAccessTime);
            if( iftLastWriteTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftLastWriteTime);
        }
    }

    public static bool SetFileTimesUtc(string FileName, DateTime? creationTimeUtc, DateTime? lastAccessTimeUtc, DateTime? lastWriteTimeUtc)
    {
        SafeFileHandle ptr = null;
        try
        {
            ptr = CreateFile(FileName, EFileAccess.GenericWrite, EFileShare.Read, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero);
            if( ptr == null || ptr.IsInvalid || ptr.IsClosed )
                return false;

            return SetFileTimesUtc(ptr, creationTimeUtc, lastAccessTimeUtc, lastWriteTimeUtc);
        }
        catch
        {
            return false;
        }
        finally
        {
            if( ptr != null && !ptr.IsInvalid && !ptr.IsClosed )
                ptr.Dispose();
        }
    }

    public static bool SetFileTimesUtc(SafeFileHandle file, DateTime? creationTimeUtc, DateTime? lastAccessTimeUtc, DateTime? lastWriteTimeUtc)
    {
        if( file == null || file.IsInvalid || file.IsClosed )
            return false;

        IntPtr iftCreationTime = IntPtr.Zero, iftLastAccessTime = IntPtr.Zero, iftLastWriteTime = IntPtr.Zero;
        try
        {
            FILETIME? ftCreationTime = null;
            FILETIME? ftLastAccessTime = null;
            FILETIME? ftLastWriteTime = null;

            if( creationTimeUtc != null )
            {
                DateTime ct = (DateTime)creationTimeUtc;
                if( ct >= MinimumTimeUtc )
                {

                    SYSTEMTIME sCt = new SYSTEMTIME(ct, DateTimeKind.Utc);
                    FILETIME fCt;

                    if( !SystemTimeToFileTime(ref sCt, out fCt) )
                        return false;

                    ftCreationTime = fCt;

                    iftCreationTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftCreationTime, iftCreationTime, false);
                }
            }

            if( lastAccessTimeUtc != null )
            {
                DateTime lat = (DateTime)lastAccessTimeUtc;

                if( lat >= MinimumTimeUtc )
                {

                    SYSTEMTIME sLat = new SYSTEMTIME(lat, DateTimeKind.Utc);
                    FILETIME fLat;


                    if( !SystemTimeToFileTime(ref sLat, out fLat) )
                        return false;

                    ftLastAccessTime = fLat;

                    iftLastAccessTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftLastAccessTime, iftLastAccessTime, false);
                }
            }

            if( lastWriteTimeUtc != null )
            {
                DateTime lwt = (DateTime)lastWriteTimeUtc;

                if( lwt >= MinimumTimeUtc )
                {
                    SYSTEMTIME sLwt = new SYSTEMTIME(lwt, DateTimeKind.Utc);

                    FILETIME fLwt;

                    if( !SystemTimeToFileTime(ref sLwt, out fLwt) )
                        return false;

                    ftLastWriteTime = fLwt;

                    iftLastWriteTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FILETIME)));
                    Marshal.StructureToPtr(ftLastWriteTime, iftLastWriteTime, false);
                }
            }


            if( SetFileTime(file, iftCreationTime, iftLastAccessTime, iftLastWriteTime) != true )
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            return true;
        }
        catch
        {
            return false;
        }
        finally
        {
            if( iftCreationTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftCreationTime);
            if( iftLastAccessTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftLastAccessTime);
            if( iftLastWriteTime != IntPtr.Zero )
                Marshal.FreeHGlobal(iftLastWriteTime);
        }
    }

    public static bool TypeAvailable()
    {
        return true;
    }
}

